package cn.xydata.es.impl;

import cn.xydata.aaa.dto.UserDetailsDto;
import cn.xydata.aaa.utils.UserUtil;
import cn.xydata.common.dto.ParamsDto;
import cn.xydata.common.dto.ResponsePageDto;
import cn.xydata.common.util.DateUtils;
import cn.xydata.common.util.JsonUtil;
import cn.xydata.common.util.LogUtil;
import cn.xydata.constant.enums.TaxProjectEnum;
import cn.xydata.dto.company.company.QueryCompanyPageSearchObjectDto;
import cn.xydata.dto.tax.comprehensive.QueryComprehensivePageSearchObjectDto;
import cn.xydata.dto.tax.payment.TaxPaymentSearchObjectDto;
import cn.xydata.es.*;
import cn.xydata.utils.PageUtil;
import cn.xydata.vo.company.company.QueryCompanyPageDataVo;
import cn.xydata.vo.tax.comprehensive.QueryComprehensivePageDataVo;
import cn.xydata.vo.tax.payment.TaxPaymentDataVo;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.InlineScript;
import co.elastic.clients.elasticsearch._types.Script;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.UpdateByQueryResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zsw
 * @date 2024/03/07
 */
@Service
public class EsServiceImpl implements EsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EsServiceImpl.class);

    private static final Long dataNum = 2000L;

    @Resource
    private ElasticsearchClient esClient;

    @Resource
    private ESClientConfig esClientConfig;

    @Override
    public ResponsePageDto<QueryCompanyPageDataVo> companyPage(ParamsDto<QueryCompanyPageSearchObjectDto> paramsDto) {
        long from = (long) (paramsDto.getCurrent() - 1) * paramsDto.getPageSize();
        long to = (long) paramsDto.getCurrent() * paramsDto.getPageSize();
        QueryCompanyPageSearchObjectDto searchObject = paramsDto.getSearchObject(QueryCompanyPageSearchObjectDto.class);
        List<Query> queryList = new ArrayList<>();
        //企业模糊查找
        if (StringUtils.isNotBlank(searchObject.getCompanyName())) {
            if (searchObject.getCompanyName().contains("*")) {
                searchObject.setCompanyName(searchObject.getCompanyName().replace("*", "\\*"));
            }
            queryList.add(EsUtil.wildcardQuery("companyName.keyword", "*" + searchObject.getCompanyName() + "*"));
        }
        //联系人模糊查找
        if (StringUtils.isNotBlank(searchObject.getContactPersonName())) {
            queryList.add(EsUtil.wildcardQuery("contactPersonName.keyword", "*" + searchObject.getContactPersonName() + "*"));
        }
        //经营地址模糊查找
        if (StringUtils.isNotBlank(searchObject.getOperatingAddress())) {
            queryList.add(EsUtil.wildcardQuery("operatingAddress.keyword", "*" + searchObject.getOperatingAddress() + "*"));
        }
        //财政行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getFinanceName())) {
            queryList.add(EsUtil.matchQuery("financeIndustryId", String.join(",", searchObject.getFinanceName())));
        }
        //财政行业匹配
        if (!CollectionUtils.isEmpty(searchObject.getPartName())) {
            String nowYear = DateUtils.format(new Date(), DateUtils.TimeFormat.PURE_YEAR);
            queryList.add(EsUtil.matchQuery("financePartId." + nowYear, String.join(",", searchObject.getPartName())));
        }
        //工商行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getBusinessName())) {
            queryList.add(EsUtil.matchQuery("businessIndustryId", String.join(",", searchObject.getBusinessName())));
        }
        //税务行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getTaxName())) {
            queryList.add(EsUtil.matchQuery("taxIndustryId", String.join(",", searchObject.getTaxName())));
        }
        //集团匹配
        if (!CollectionUtils.isEmpty(searchObject.getGroupName())) {
            queryList.add(EsUtil.matchQuery("groupId", String.join(",", searchObject.getGroupName())));
        }
        BoolQuery boolQuery = new BoolQuery.Builder().must(queryList).build();
        Query queryBool = new Query.Builder().bool(boolQuery).build();

        //总数据量
        String totalAggregationName = "total";
        SearchResponse<Company> totalSearch = null;
        try {
            totalSearch = esClient.search(builder -> builder
                            .index(esClientConfig.getCompanyIndex())
                            .query(queryBool)
                            .aggregations(totalAggregationName,  EsUtil.cardinalityAggregation("companyId.keyword"))
                    , Company.class);
        } catch (IOException e) {
            LOGGER.error("ES企业查询数据总量查询异常");
            e.printStackTrace();
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("ES企业查询数据总量查询异常", e, userInfo[0], userInfo[1]);
            return PageUtil.getBlankResponsePage(paramsDto);
        }
        long total = (long) totalSearch.aggregations().get(totalAggregationName).cardinality().value();

        SearchResponse<Company> search = null;
        try {
            search = esClient.search(builder -> builder
                    .index(esClientConfig.getCompanyIndex())
                    .query(queryBool)
                    .from((int) from)
                    .size((int) (to - 1))
                    .sort(EsUtil.sortOptions("gmtModified", false)), Company.class);
        } catch (IOException e) {
            LOGGER.error("ES企业分页查询异常");
            e.printStackTrace();
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("ES企业分页查询异常", e, userInfo[0], userInfo[1]);
            return PageUtil.getBlankResponsePage(paramsDto);
        }

        List<Company> collect = search.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
        PageInfo<Company> pageInfo = new PageInfo<>(collect);
        List<QueryCompanyPageDataVo> res = collect.stream().map(QueryCompanyPageDataVo::new).collect(Collectors.toList());
        ResponsePageDto<QueryCompanyPageDataVo> responsePageDto = PageUtil.getResponsePageDto(pageInfo, res);
        responsePageDto.setTotal(total);
        responsePageDto.setFirst(paramsDto.getCurrent() == 1);
        responsePageDto.setIsLast(to == total);
        return responsePageDto;
    }

    @Override
    public ResponsePageDto<QueryComprehensivePageDataVo> comprehensivePage(ParamsDto<QueryComprehensivePageSearchObjectDto> paramsDto) {
        long from = (long) (paramsDto.getCurrent() - 1) * paramsDto.getPageSize();
        long to = (long) paramsDto.getCurrent() * paramsDto.getPageSize();
        QueryComprehensivePageSearchObjectDto searchObject = paramsDto.getSearchObject(QueryComprehensivePageSearchObjectDto.class);

        //搜索条件
        List<Query> queryList = new ArrayList<>();
        //企业模糊查找
        if (StringUtils.isNotBlank(searchObject.getCompanyName())) {
            if (searchObject.getCompanyName().contains("*")) {
                searchObject.setCompanyName(searchObject.getCompanyName().replace("*", "\\*"));
            }
            queryList.add(EsUtil.wildcardQuery("companyName.keyword", "*" + searchObject.getCompanyName() + "*"));
        }
        //集团精确匹配
        if (StringUtils.isNotBlank(searchObject.getGroupId())) {
            queryList.add(EsUtil.termQuery("groupId", searchObject.getGroupId()));
        }
        //年份查询
        if (searchObject.getTaxYear() == null) {
            searchObject.setTaxYear(LocalDate.now().getYear());
        }
        queryList.add(EsUtil.termQuery("taxYear", searchObject.getTaxYear().toString()));
        //搜索条件封装
        BoolQuery boolQuery = new BoolQuery.Builder().must(queryList).build();
        Query queryBool = new Query.Builder().bool(boolQuery).build();

        //总数据量
        String totalAggregationName = "total";
        SearchResponse<CompanyTax> totalSearch = null;
        try {
            totalSearch = esClient.search(builder -> builder
                            .index(esClientConfig.getCompanyTaxIndex())
                            .query(queryBool)
                            .aggregations(totalAggregationName,  EsUtil.cardinalityAggregation("companyId.keyword"))
                    , CompanyTax.class);
        } catch (IOException e) {
            LOGGER.error("ES综合查询数据总量查询异常");
            e.printStackTrace();
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("ES综合查询数据总量查询异常", e, userInfo[0], userInfo[1]);
            return PageUtil.getBlankResponsePage(paramsDto);
        }
        long total = (long) totalSearch.aggregations().get(totalAggregationName).cardinality().value();
        if (to >= dataNum || to == 0L) {
            return PageUtil.getBlankResponsePage(paramsDto);
        }

        //terms聚合
        HashMap<String, SortOrder> orderMap = new HashMap<>();
        if (null != searchObject.getOrderWay()) {
            if (searchObject.getOrderWay().equals("taxAmount")) {
                orderMap.put("taxAmount", SortOrder.Asc);
            } else {
                orderMap.put("taxAmount", SortOrder.Desc);
            }
        } else {
            orderMap.put("taxAmount", SortOrder.Desc);
        }
        List<Map<String, SortOrder>> orderList = new ArrayList<>();
        orderList.add(orderMap);
        TermsAggregation termsAggregation = new TermsAggregation.Builder().field("companyId.keyword")
                .order(orderList).size((int)to).build();

        //sum嵌套脚本索引
        List<String> docList = new ArrayList<>();
        for (TaxProjectEnum taxProjectEnum : TaxProjectEnum.values()) {
            docList.add(taxProjectEnum.name());
        }
        SumAggregation sumAggregation = new SumAggregation.Builder().script(EsUtil.sumInlineScript(docList)).build();
        Aggregation totalAmountAggregation = new Aggregation.Builder().sum(sumAggregation).build();

        //聚合整合
        String aggregationName = "companyTax";
        Aggregation aggregation = new Aggregation.Builder().terms(termsAggregation)
                .aggregations("taxAmount", totalAmountAggregation)
                .aggregations("companyInfo", EsUtil.topHitsAggregation((int) 1))
                .build();
        //查询数据
        SearchResponse<CompanyTax> search = null;
        try {
            search = esClient.search(builder -> builder
                            .index(esClientConfig.getCompanyTaxIndex())
                            .query(queryBool)
                            .size(0)
                            .aggregations(aggregationName, aggregation)
                    , CompanyTax.class);
        } catch (IOException e) {
            LOGGER.error("ES综合查询聚合数据异常");
            e.printStackTrace();
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("ES综合查询聚合数据异常", e, userInfo[0], userInfo[1]);
            return PageUtil.getBlankResponsePage(paramsDto);
        }

        //数据整理
        List<QueryComprehensivePageDataVo> res = new ArrayList<>();
        Aggregate companyTaxAggregate = search.aggregations().get(aggregationName);
        List<StringTermsBucket> bucketList = companyTaxAggregate.sterms().buckets().array();
        for (int i = (int)from; i < (int)to; i++) {
            if (i >= bucketList.size()) {
                break;
            }
            StringTermsBucket bucket = bucketList.get(i);
            Map<String, Aggregate> collect = bucket.aggregations().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            CompanyTax companyTax = collect.get("companyInfo").topHits().hits().hits().stream().map(Hit::source).collect(Collectors.toList()).get(0).to(CompanyTax.class);
            double taxAmountValue = collect.get("taxAmount").sum().value();
            BigDecimal taxAmount = BigDecimal.valueOf(taxAmountValue).setScale(2, RoundingMode.HALF_UP);
            QueryComprehensivePageDataVo tmp = new QueryComprehensivePageDataVo(companyTax, taxAmount);
            res.add(tmp);
        }
        PageInfo<QueryComprehensivePageDataVo> pageInfo = new PageInfo<>(res);
        ResponsePageDto<QueryComprehensivePageDataVo> responsePageDto = PageUtil.getResponsePageDto(pageInfo);
        responsePageDto.setTotal(total);
        responsePageDto.setFirst(paramsDto.getCurrent() == 1);
        responsePageDto.setIsLast(to == total);
        return responsePageDto;
    }

    @Override
    public ResponsePageDto<TaxPaymentDataVo> taxPaymentPage(ParamsDto<TaxPaymentSearchObjectDto> paramsDto) {
        long from = (long) (paramsDto.getCurrent() - 1) * paramsDto.getPageSize();
        long to = (long) paramsDto.getCurrent() * paramsDto.getPageSize();
        TaxPaymentSearchObjectDto searchObject = paramsDto.getSearchObject(TaxPaymentSearchObjectDto.class);

        Query taxPaymentQuery = getTaxPaymentQuery(searchObject);

        //总数据量
        String totalAggregationName = "total";
        SearchResponse<CompanyTax> totalSearch = null;
        try {
            totalSearch = esClient.search(builder -> builder
                            .index(esClientConfig.getCompanyTaxIndex())
                            .query(taxPaymentQuery)
                            .aggregations(totalAggregationName,  EsUtil.cardinalityAggregation("taxYearCompanyId.keyword"))
                    , CompanyTax.class);
        } catch (IOException e) {
            LOGGER.error("ES税务查询数据总量查询异常");
            e.printStackTrace();
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("ES税务查询数据总量查询异常", e, userInfo[0], userInfo[1]);
            return PageUtil.getBlankResponsePage(paramsDto);
        }
        long total = (long) totalSearch.aggregations().get(totalAggregationName).cardinality().value();
        if (to >= dataNum || to == 0L) {
            return PageUtil.getBlankResponsePage(paramsDto);
        }

        //term聚合
        List<Map<String, SortOrder>> orderList = new ArrayList<>();
        HashMap<String, SortOrder> orderMap = new HashMap<>();
        orderMap.put("taxYear", SortOrder.Desc);
        orderList.add(orderMap);
        orderMap = new HashMap<>();
        if (null != searchObject.getOrderWay()) {
            switch (searchObject.getOrderWay()) {
                case "totalAmount": {
                    orderMap.put("totalAmount", SortOrder.Asc);
                    break;
                }
                case "taxTotalAmount": {
                    orderMap.put("taxTotalAmount", SortOrder.Asc);
                    break;
                }
                case "unTaxTotalAmount": {
                    orderMap.put("unTaxTotalAmount", SortOrder.Asc);
                    break;
                }
                case "offsetTotal": {
                    orderMap.put("offsetTotal", SortOrder.Asc);
                    break;
                }
                case "valueAddedTaxSubtotal": {
                    orderMap.put("valueAddedTaxSubtotal", SortOrder.Asc);
                    break;
                }
                case "totalAmount_desc": {
                    orderMap.put("totalAmount", SortOrder.Desc);
                    break;
                }
                case "taxTotalAmount_desc": {
                    orderMap.put("taxTotalAmount", SortOrder.Desc);
                    break;
                }
                case "unTaxTotalAmount_desc": {
                    orderMap.put("unTaxTotalAmount", SortOrder.Desc);
                    break;
                }
                case "offsetTotal_desc": {
                    orderMap.put("offsetTotal", SortOrder.Desc);
                    break;
                }
                case "valueAddedTaxSubtotal_desc": {
                    orderMap.put("valueAddedTaxSubtotal", SortOrder.Desc);
                    break;
                }
                default:
                    orderMap.put("totalAmount", SortOrder.Desc);
                    break;
            }
        } else {
            orderMap.put("totalAmount", SortOrder.Desc);
        }
        orderList.add(orderMap);

        TermsAggregation termsAggregation = new TermsAggregation.Builder().field("taxYearCompanyId.keyword")
                .order(orderList).size((int)to).build();
        //数据聚合
        Aggregation aggregation = new Aggregation.Builder().terms(termsAggregation)
                .aggregations("totalAmount", EsUtil.sumAggregation("totalAmount"))
                .aggregations("taxTotalAmount", EsUtil.sumAggregation("taxTotalAmount"))
                .aggregations("unTaxTotalAmount", EsUtil.sumAggregation("unTaxTotalAmount"))
                .aggregations("offsetTotal", EsUtil.sumAggregation("offsetTotal"))
                .aggregations("valueAddedTaxSubtotal", EsUtil.sumAggregation("valueAddedTaxSubtotal"))
                .aggregations("commonValueAddedTax", EsUtil.sumAggregation("commonValueAddedTax"))
                .aggregations("offsetValueAddedTax", EsUtil.sumAggregation("offsetValueAddedTax"))
                .aggregations("exportRefundTax", EsUtil.sumAggregation("exportRefundTax"))
                .aggregations("changeValueAddedTax", EsUtil.sumAggregation("changeValueAddedTax"))
                .aggregations("consumeTax", EsUtil.sumAggregation("consumeTax"))
                .aggregations("businessTax", EsUtil.sumAggregation("businessTax"))
                .aggregations("financialBusinessTax", EsUtil.sumAggregation("financialBusinessTax"))
                .aggregations("companyIncomeTax", EsUtil.sumAggregation("companyIncomeTax"))
                .aggregations("personIncomeTax", EsUtil.sumAggregation("personIncomeTax"))
                .aggregations("resourceTax", EsUtil.sumAggregation("resourceTax"))
                .aggregations("cityConstructTax", EsUtil.sumAggregation("cityConstructTax"))
                .aggregations("houseTax", EsUtil.sumAggregation("houseTax"))
                .aggregations("stampTax", EsUtil.sumAggregation("stampTax"))
                .aggregations("urbanLandUseTax", EsUtil.sumAggregation("urbanLandUseTax"))
                .aggregations("landValueAddedTax", EsUtil.sumAggregation("landValueAddedTax"))
                .aggregations("carBoatTax", EsUtil.sumAggregation("carBoatTax"))
                .aggregations("farmlandUsedTax", EsUtil.sumAggregation("farmlandUsedTax"))
                .aggregations("deedTax", EsUtil.sumAggregation("deedTax"))
                .aggregations("otherTaxIncome", EsUtil.sumAggregation("otherTaxIncome"))
                .aggregations("educationSurchargeIncome", EsUtil.sumAggregation("educationSurchargeIncome"))
                .aggregations("localEducationSurchargeIncome", EsUtil.sumAggregation("localEducationSurchargeIncome"))
                .aggregations("culturalConstructionFee", EsUtil.sumAggregation("culturalConstructionFee"))
                .aggregations("localWaterConstructionIncome", EsUtil.sumAggregation("localWaterConstructionIncome"))
                .aggregations("deformitySecurityIncome", EsUtil.sumAggregation("deformitySecurityIncome"))
                .aggregations("environmentalProtectionTax", EsUtil.sumAggregation("environmentalProtectionTax"))
                .aggregations("companyInfo", EsUtil.topHitsAggregation((int) 1))
                .aggregations("taxYear", EsUtil.maxAggregation("taxYear"))
                .build();


        //聚合统计
        String aggregationName = "taxPayment";
        SearchResponse<CompanyTax> search = null;
        try {
            search = esClient.search(builder -> builder
                            .index(esClientConfig.getCompanyTaxIndex())
                            .size(0)
                            .query(taxPaymentQuery)
                            .aggregations(aggregationName, aggregation)
                    , CompanyTax.class);
        } catch (IOException e) {
            LOGGER.error("ES税务查询数据分页查询异常");
            e.printStackTrace();
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("ES税务查询数据分页查询异常", e, userInfo[0], userInfo[1]);
            return PageUtil.getBlankResponsePage(paramsDto);
        }

        List<TaxPaymentDataVo> res = new ArrayList<>();
        Aggregate companyTaxAggregate = search.aggregations().get(aggregationName);
        List<StringTermsBucket> bucketList = companyTaxAggregate.sterms().buckets().array();
        for (int i = (int)from; i < (int)to; i++) {
            if (i >= bucketList.size()) {
                break;
            }
            StringTermsBucket bucket = bucketList.get(i);
            Integer taxYear = Integer.parseInt(bucket.key().split("#")[0]);
            Map<String, Aggregate> aggregationMap = bucket.aggregations().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            TaxPaymentDataVo tmp = new TaxPaymentDataVo(taxYear, aggregationMap, searchObject.getAmountUnit() != null && "W_YUAN".equals(searchObject.getAmountUnit()), false);
            res.add(tmp);
        }

        PageInfo<TaxPaymentDataVo> pageInfo = new PageInfo<>(res);
        ResponsePageDto<TaxPaymentDataVo> responsePageDto = PageUtil.getResponsePageDto(pageInfo);
        responsePageDto.setTotal(total);
        responsePageDto.setFirst(paramsDto.getCurrent() == 1);
        responsePageDto.setIsLast(to == total);
        return responsePageDto;
    }

    @Override
    public TaxPaymentDataVo queryTaxPaymentTotal(TaxPaymentSearchObjectDto searchObject) {
        Query taxPaymentQuery = getTaxPaymentQuery(searchObject);

        //聚合统计
        SearchResponse<CompanyTax> search = null;
        try {
            search = esClient.search(builder -> builder
                    .index(esClientConfig.getCompanyTaxIndex())
                    .size(0)
                    .query(taxPaymentQuery)
                    .aggregations("totalAmount", EsUtil.sumAggregation("totalAmount"))
                    .aggregations("taxTotalAmount", EsUtil.sumAggregation("taxTotalAmount"))
                    .aggregations("unTaxTotalAmount", EsUtil.sumAggregation("unTaxTotalAmount"))
                    .aggregations("offsetTotal", EsUtil.sumAggregation("offsetTotal"))
                    .aggregations("valueAddedTaxSubtotal", EsUtil.sumAggregation("valueAddedTaxSubtotal"))
                    .aggregations("commonValueAddedTax", EsUtil.sumAggregation("commonValueAddedTax"))
                    .aggregations("offsetValueAddedTax", EsUtil.sumAggregation("offsetValueAddedTax"))
                    .aggregations("exportRefundTax", EsUtil.sumAggregation("exportRefundTax"))
                    .aggregations("changeValueAddedTax", EsUtil.sumAggregation("changeValueAddedTax"))
                    .aggregations("consumeTax", EsUtil.sumAggregation("consumeTax"))
                    .aggregations("businessTax", EsUtil.sumAggregation("businessTax"))
                    .aggregations("financialBusinessTax", EsUtil.sumAggregation("financialBusinessTax"))
                    .aggregations("companyIncomeTax", EsUtil.sumAggregation("companyIncomeTax"))
                    .aggregations("personIncomeTax", EsUtil.sumAggregation("personIncomeTax"))
                    .aggregations("resourceTax", EsUtil.sumAggregation("resourceTax"))
                    .aggregations("cityConstructTax", EsUtil.sumAggregation("cityConstructTax"))
                    .aggregations("houseTax", EsUtil.sumAggregation("houseTax"))
                    .aggregations("stampTax", EsUtil.sumAggregation("stampTax"))
                    .aggregations("urbanLandUseTax", EsUtil.sumAggregation("urbanLandUseTax"))
                    .aggregations("landValueAddedTax", EsUtil.sumAggregation("landValueAddedTax"))
                    .aggregations("carBoatTax", EsUtil.sumAggregation("carBoatTax"))
                    .aggregations("farmlandUsedTax", EsUtil.sumAggregation("farmlandUsedTax"))
                    .aggregations("deedTax", EsUtil.sumAggregation("deedTax"))
                    .aggregations("otherTaxIncome", EsUtil.sumAggregation("otherTaxIncome"))
                    .aggregations("educationSurchargeIncome", EsUtil.sumAggregation("educationSurchargeIncome"))
                    .aggregations("localEducationSurchargeIncome", EsUtil.sumAggregation("localEducationSurchargeIncome"))
                    .aggregations("culturalConstructionFee", EsUtil.sumAggregation("culturalConstructionFee"))
                    .aggregations("localWaterConstructionIncome", EsUtil.sumAggregation("localWaterConstructionIncome"))
                    .aggregations("deformitySecurityIncome", EsUtil.sumAggregation("deformitySecurityIncome"))
                    .aggregations("environmentalProtectionTax", EsUtil.sumAggregation("environmentalProtectionTax"))
                    , CompanyTax.class);
        } catch (IOException e) {
            TaxPaymentDataVo taxPaymentDataVo = new TaxPaymentDataVo();
            taxPaymentDataVo.setCompanyName("合计");
            return taxPaymentDataVo;
        }

        Map<String, Aggregate> aggregationMap = search.aggregations();
        return new TaxPaymentDataVo(null, aggregationMap, searchObject.getAmountUnit() != null && "W_YUAN".equals(searchObject.getAmountUnit()), true);
    }

    /**
     * 根据税务查询数据获取查询条件
     *
     * @param searchObject 查询条件
     * @return 查询条件
     */
    private static Query getTaxPaymentQuery(TaxPaymentSearchObjectDto searchObject) {
        //查询条件封装
        List<Query> queryList = new ArrayList<>();
        //企业模糊查找
        if (StringUtils.isNotBlank(searchObject.getCompanyName())) {
            if (searchObject.getCompanyName().contains("*")) {
                searchObject.setCompanyName(searchObject.getCompanyName().replace("*", "\\*"));
            }
            queryList.add(EsUtil.wildcardQuery("companyName.keyword", "*" + searchObject.getCompanyName() + "*"));
        }
        //纳税人识别号查找
        if (StringUtils.isNotBlank(searchObject.getTaxpayersCreditCode())) {
            queryList.add(EsUtil.termQuery("taxpayersCreditCode", searchObject.getTaxpayersCreditCode()));
        }
        //集团匹配
        if (!CollectionUtils.isEmpty(searchObject.getGroupIds())) {
            queryList.add(EsUtil.matchQuery("groupId", String.join(",", searchObject.getGroupIds())));
        }
        //财政行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getFinanceIndustryCodes())) {
            queryList.add(EsUtil.matchQuery("financeIndustryId", String.join(",", searchObject.getFinanceIndustryCodes())));
        }
        //财政行业匹配
        if (!CollectionUtils.isEmpty(searchObject.getFinancePartCodes())) {
            queryList.add(EsUtil.matchQuery("financePartId", String.join(",", searchObject.getFinancePartCodes())));
        }
        //工商行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getBusinessIndustryCodes())) {
            queryList.add(EsUtil.matchQuery("businessIndustryId", String.join(",", searchObject.getBusinessIndustryCodes())));
        }
        //税务行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getTaxIndustryCodes())) {
            queryList.add(EsUtil.matchQuery("taxIndustryId", String.join(",", searchObject.getTaxIndustryCodes())));
        }
        //企业属性逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getCompanyAttributeCodes())) {
            queryList.add(EsUtil.matchQuery("attributeId", String.join(",", searchObject.getCompanyAttributeCodes())));
        }
        //金额类型
        if (StringUtils.isNotBlank(searchObject.getAmountType()) && searchObject.getAmountMax() != null && searchObject.getAmountMin() != null) {
            queryList.add(EsUtil.rangeQuery(searchObject.getAmountType(), searchObject.getAmountMax(), true, searchObject.getAmountMin(), true));
        }
        //月份
        if (searchObject.getTaxMonthMin() != null && searchObject.getTaxMonthMax() != null) {
            queryList.add(EsUtil.rangeQuery("taxMonth", searchObject.getTaxMonthMin(), true, searchObject.getTaxMonthMax(), true));
        }
        //年份
        if (searchObject.getTaxYear() != null) {
            queryList.add(EsUtil.termQuery("taxYear", String.valueOf(searchObject.getTaxYear())));
        }
        //成立日期
        if (searchObject.getEstablishStartDate() != null && searchObject.getEstablishEndDate() != null) {
            queryList.add(EsUtil.rangeQuery("establishDate", searchObject.getEstablishStartDate(), true, searchObject.getEstablishEndDate(), true));
        }

        //查询条件统计
        List<Query> mustNotList = new ArrayList<>();
        mustNotList.add(EsUtil.termQuery("taxYear", "-1"));
        BoolQuery boolQuery = new BoolQuery.Builder().must(queryList).mustNot(mustNotList).build();
        return new Query.Builder().bool(boolQuery).build();
    }

    @Override
    @Async
    public void insert(String indexName, String docId, Object o) {
        try {
            esClient.index(idx -> idx.index(indexName).id(docId).document(o));
        } catch (IOException e) {
            LOGGER.error("新增索引文档失败!索引:{},文档id:{},文档信息:{}", indexName, docId, JsonUtil.toJSONString(o));
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("新增索引文档失败", e, userInfo[0], userInfo[1]);
        }

    }

    @Override
    @Async
    public void update(String indexName, Query query, JsonData jsonData) {
        InlineScript inlineScript = new InlineScript.Builder().source("ctx._source = params.newDoc").params("newDoc", jsonData).build();
        Script script = new Script.Builder().inline(inlineScript).build();
        try {
            UpdateByQueryResponse company = esClient.updateByQuery(builder -> builder.index(indexName).script(script).query(query));
        } catch (IOException e) {
            LOGGER.error("修改索引文档失败!索引:{},查询条件:{},数据:{}", indexName, query, jsonData);
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("修改索引文档失败", e, userInfo[0], userInfo[1]);
        }
    }

    @Override
    @Async
    public void deleteByQuery(String indexName, Query query) {
        try {
            esClient.deleteByQuery(builder -> builder.index(indexName).query(query));
        } catch (IOException e) {
            LOGGER.error("根据查询条件删除索引文档失败!索引:{},查询条件:{}", indexName, query);
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("根据查询条件删除索引文档失败", e, userInfo[0], userInfo[1]);
        }
    }

    @Override
    @Async
    public void deleteByDocId(String indexName, String docId) {
        try {
            esClient.delete(builder -> builder.index(indexName).id(docId));
        } catch (IOException e) {
            LOGGER.error("根据文档id删除索引文档失败!索引:{},文档id:{}", indexName, docId);
            String[] userInfo = getUserIdAndUserName();
            LogUtil.addErrorLog("根据文档id删除索引文档失败", e, userInfo[0], userInfo[1]);
        }
    }

    /**
     * 返回当前登录用户信息的的userId和userName
     *
     * @return 当前登录用户信息的的userId和userName
     */
    private String[] getUserIdAndUserName() {
        String userId = null;
        String userName = null;
        UserDetailsDto loginUser = UserUtil.getLoginUser();
        if (null != loginUser) {
            userId = loginUser.getId();
            userName = loginUser.getUsername();
        }
        return new String[]{userId, userName};
    }
}
